package kinect.viewer;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import javax.swing.JOptionPane;
import javax.swing.Timer;
import kinect.storage.KinectStorageProtos.Sequence;
import kinect.storage.KinectStorageProtos.Frame;
import kinect.storage.KinectStorageProtos.Joint;
import kinect.storage.KinectStorageProtos.Point3D;
import kinect.util.KinectPreferences;
import kinect.util.PrintfFormat;

/**
 *
 * @author samo
 */
public class Viewer extends javax.swing.JFrame {
//    String[] recordLabels = {"none","gest1","gest2","gest3","gest4","gest5","gest6"};
//    String[] frameLabels = {"none","gest1","gest2","gest3","gest4","gest5","gest6"};
    String[] recordLabels;
    String[] frameLabels;
    KinectPreferences preferences;
    //String recPath = "/home/samo/recordings/";
    String recPath;
    String[] recordigns;
    File recording;
    File dir;
    Sequence sequence;
    SkeletonProjective skeletonProjective;
    HashMap<Integer,Frame> idToFrame;
    Timer playTimer;
    Frame frameSelected;
    Frame frameStart;
    Frame frameEnd;
    boolean change;
    
    /** Creates new form Viewer */
    public Viewer() {
        // Load preferences
        preferences = new KinectPreferences();
        preferences.load();
        recordLabels = preferences.getRecordingLabels();
        frameLabels = preferences.getFrameLabels();
        
        // Init Viewer components
        initComponents();
       
        // Set initial Values
        initSetupAndLoad();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        jPanelProjective = new javax.swing.JPanel();
        jPanelRecordings = new javax.swing.JPanel();
        jTextFieldPath = new javax.swing.JTextField();
        jScrollPaneRecordings = new javax.swing.JScrollPane();
        jListRecordings = new javax.swing.JList();
        jPanelRecListButton = new javax.swing.JPanel();
        jButtonSetPath = new javax.swing.JButton();
        jButtonRefresh = new javax.swing.JButton();
        jPanelPlay = new javax.swing.JPanel();
        jPanelPlayAux = new javax.swing.JPanel();
        jLabelFPS = new javax.swing.JLabel();
        jFormattedTextFieldFPS = new javax.swing.JFormattedTextField();
        jButtonPlay = new javax.swing.JButton();
        jButtonStop = new javax.swing.JButton();
        jPanelFrames = new javax.swing.JPanel();
        jButtonNext = new javax.swing.JButton();
        jButtonPrevious = new javax.swing.JButton();
        jScrollPaneFrames = new javax.swing.JScrollPane();
        jListFrames = new javax.swing.JList();
        jPanelPreview = new javax.swing.JPanel();
        jScrollPanePreview = new javax.swing.JScrollPane();
        jPanelContainer = new javax.swing.JPanel();
        jPanelRecordLabel = new javax.swing.JPanel();
        jPanelRecordLabelAux = new javax.swing.JPanel();
        jLabelRecordLabelId = new javax.swing.JLabel();
        jLabelRecordLabelValue = new javax.swing.JLabel();
        jScrollPaneRecordLabels = new javax.swing.JScrollPane();
        jListRecordLabels = new javax.swing.JList();
        jPanelFrame = new javax.swing.JPanel();
        jPanelFrameEdit = new javax.swing.JPanel();
        jButtonFrameEdit = new javax.swing.JButton();
        jLabelFrameId = new javax.swing.JLabel();
        jLabelFrameValue = new javax.swing.JLabel();
        jPanelNewSequence = new javax.swing.JPanel();
        jLabelStartId = new javax.swing.JLabel();
        jLabelEndId = new javax.swing.JLabel();
        jLabelStartValue = new javax.swing.JLabel();
        jButtonStartSet = new javax.swing.JButton();
        jLabelEndValue = new javax.swing.JLabel();
        jButtonEndSet = new javax.swing.JButton();
        jButtonReset = new javax.swing.JButton();
        jButtonSaveNewSequence = new javax.swing.JButton();
        jLabelTotalId = new javax.swing.JLabel();
        jLabelTotalValue = new javax.swing.JLabel();
        jButtonSaveChanges = new javax.swing.JButton();
        jScrollPaneFrameLabel = new javax.swing.JScrollPane();
        jListFrameLabels = new javax.swing.JList();
        jLabelFrameLabel = new javax.swing.JLabel();
        jLabelFrameLabelValue = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setResizable(false);

        jPanelProjective.setBorder(javax.swing.BorderFactory.createTitledBorder("Projective View"));
        jPanelProjective.setPreferredSize(new java.awt.Dimension(659, 525));

        jPanelRecordings.setBorder(javax.swing.BorderFactory.createTitledBorder("Recordings"));
        jPanelRecordings.setPreferredSize(new java.awt.Dimension(250, 450));

        jTextFieldPath.setToolTipText("Path");
        jTextFieldPath.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jTextFieldPathActionPerformed(evt);
            }
        });

        jListRecordings.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        jListRecordings.setToolTipText("Recordings list");
        jListRecordings.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
                jListRecordingsValueChanged(evt);
            }
        });
        jScrollPaneRecordings.setViewportView(jListRecordings);

        jButtonSetPath.setText("Set Path");
        jButtonSetPath.setToolTipText("Set path");
        jButtonSetPath.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonSetPathActionPerformed(evt);
            }
        });
        jPanelRecListButton.add(jButtonSetPath);

        jButtonRefresh.setText("Refresh");
        jButtonRefresh.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonRefreshActionPerformed(evt);
            }
        });
        jPanelRecListButton.add(jButtonRefresh);

        javax.swing.GroupLayout jPanelRecordingsLayout = new javax.swing.GroupLayout(jPanelRecordings);
        jPanelRecordings.setLayout(jPanelRecordingsLayout);
        jPanelRecordingsLayout.setHorizontalGroup(
            jPanelRecordingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanelRecordingsLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanelRecordingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanelRecordingsLayout.createSequentialGroup()
                        .addGroup(jPanelRecordingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                            .addComponent(jScrollPaneRecordings, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 214, Short.MAX_VALUE)
                            .addComponent(jTextFieldPath, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 214, Short.MAX_VALUE))
                        .addGap(12, 12, 12))
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanelRecordingsLayout.createSequentialGroup()
                        .addComponent(jPanelRecListButton, javax.swing.GroupLayout.DEFAULT_SIZE, 214, Short.MAX_VALUE)
                        .addContainerGap())))
        );
        jPanelRecordingsLayout.setVerticalGroup(
            jPanelRecordingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanelRecordingsLayout.createSequentialGroup()
                .addComponent(jTextFieldPath, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPaneRecordings, javax.swing.GroupLayout.DEFAULT_SIZE, 408, Short.MAX_VALUE)
                .addGap(8, 8, 8)
                .addComponent(jPanelRecListButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );

        jPanelPlay.setBorder(javax.swing.BorderFactory.createTitledBorder("Play recording"));

        jLabelFPS.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        jLabelFPS.setText("FPS:");

        jFormattedTextFieldFPS.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter(new java.text.DecimalFormat("#0"))));
        jFormattedTextFieldFPS.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jFormattedTextFieldFPSActionPerformed(evt);
            }
        });

        jButtonPlay.setText("Play");
        jButtonPlay.setEnabled(false);
        jButtonPlay.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonPlayActionPerformed(evt);
            }
        });

        jButtonStop.setText("Stop");
        jButtonStop.setEnabled(false);
        jButtonStop.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonStopActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout jPanelPlayAuxLayout = new javax.swing.GroupLayout(jPanelPlayAux);
        jPanelPlayAux.setLayout(jPanelPlayAuxLayout);
        jPanelPlayAuxLayout.setHorizontalGroup(
            jPanelPlayAuxLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanelPlayAuxLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanelPlayAuxLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanelPlayAuxLayout.createSequentialGroup()
                        .addComponent(jLabelFPS)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jFormattedTextFieldFPS, javax.swing.GroupLayout.PREFERRED_SIZE, 0, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(jPanelPlayAuxLayout.createSequentialGroup()
                        .addComponent(jButtonPlay)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(jButtonStop)))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        jPanelPlayAuxLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {jButtonPlay, jButtonStop, jFormattedTextFieldFPS, jLabelFPS});

        jPanelPlayAuxLayout.setVerticalGroup(
            jPanelPlayAuxLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanelPlayAuxLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanelPlayAuxLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabelFPS)
                    .addComponent(jFormattedTextFieldFPS, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanelPlayAuxLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jButtonPlay)
                    .addComponent(jButtonStop))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        jPanelPlay.add(jPanelPlayAux);

        jPanelFrames.setBorder(javax.swing.BorderFactory.createTitledBorder("Frames"));

        jButtonNext.setText("Next");
        jButtonNext.setEnabled(false);
        jButtonNext.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonNextActionPerformed(evt);
            }
        });

        jButtonPrevious.setText("Previous");
        jButtonPrevious.setEnabled(false);
        jButtonPrevious.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonPreviousActionPerformed(evt);
            }
        });

        jListFrames.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        jListFrames.setToolTipText("Select frame");
        jListFrames.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
                jListFramesValueChanged(evt);
            }
        });
        jScrollPaneFrames.setViewportView(jListFrames);

        javax.swing.GroupLayout jPanelFramesLayout = new javax.swing.GroupLayout(jPanelFrames);
        jPanelFrames.setLayout(jPanelFramesLayout);
        jPanelFramesLayout.setHorizontalGroup(
            jPanelFramesLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanelFramesLayout.createSequentialGroup()
                .addGap(12, 12, 12)
                .addComponent(jScrollPaneFrames, javax.swing.GroupLayout.DEFAULT_SIZE, 214, Short.MAX_VALUE)
                .addContainerGap(12, Short.MAX_VALUE))
            .addGroup(jPanelFramesLayout.createSequentialGroup()
                .addGap(38, 38, 38)
                .addComponent(jButtonPrevious)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jButtonNext)
                .addContainerGap(52, Short.MAX_VALUE))
        );

        jPanelFramesLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {jButtonNext, jButtonPrevious});

        jPanelFramesLayout.setVerticalGroup(
            jPanelFramesLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanelFramesLayout.createSequentialGroup()
                .addComponent(jScrollPaneFrames, javax.swing.GroupLayout.DEFAULT_SIZE, 158, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanelFramesLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
                    .addComponent(jButtonPrevious)
                    .addComponent(jButtonNext))
                .addContainerGap())
        );

        jPanelPreview.setBorder(javax.swing.BorderFactory.createTitledBorder("Preview"));

        jScrollPanePreview.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
        jScrollPanePreview.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
        jScrollPanePreview.setViewportBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1));
        jScrollPanePreview.setDoubleBuffered(true);
        jScrollPanePreview.setOpaque(false);

        jPanelContainer.setMinimumSize(new java.awt.Dimension(0, 0));
        jPanelContainer.setOpaque(false);
        jPanelContainer.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT, 3, 0));
        jScrollPanePreview.setViewportView(jPanelContainer);

        javax.swing.GroupLayout jPanelPreviewLayout = new javax.swing.GroupLayout(jPanelPreview);
        jPanelPreview.setLayout(jPanelPreviewLayout);
        jPanelPreviewLayout.setHorizontalGroup(
            jPanelPreviewLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanelPreviewLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPanePreview, javax.swing.GroupLayout.PREFERRED_SIZE, 635, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        jPanelPreviewLayout.setVerticalGroup(
            jPanelPreviewLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanelPreviewLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPanePreview, javax.swing.GroupLayout.DEFAULT_SIZE, 181, Short.MAX_VALUE)
                .addContainerGap())
        );

        jPanelRecordLabel.setBorder(javax.swing.BorderFactory.createTitledBorder("Record Label "));

        jPanelRecordLabelAux.setLayout(new java.awt.GridBagLayout());

        jLabelRecordLabelId.setText("Label:");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        jPanelRecordLabelAux.add(jLabelRecordLabelId, gridBagConstraints);

        jLabelRecordLabelValue.setText("none");
        jLabelRecordLabelValue.setToolTipText("");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        jPanelRecordLabelAux.add(jLabelRecordLabelValue, gridBagConstraints);

        jScrollPaneRecordLabels.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        jScrollPaneRecordLabels.setPreferredSize(null);

        jListRecordLabels.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        jListRecordLabels.setToolTipText("Set record label");
        jListRecordLabels.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
                jListRecordLabelsValueChanged(evt);
            }
        });
        jScrollPaneRecordLabels.setViewportView(jListRecordLabels);

        javax.swing.GroupLayout jPanelRecordLabelLayout = new javax.swing.GroupLayout(jPanelRecordLabel);
        jPanelRecordLabel.setLayout(jPanelRecordLabelLayout);
        jPanelRecordLabelLayout.setHorizontalGroup(
            jPanelRecordLabelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanelRecordLabelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanelRecordLabelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPaneRecordLabels, javax.swing.GroupLayout.DEFAULT_SIZE, 281, Short.MAX_VALUE)
                    .addComponent(jPanelRecordLabelAux, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap())
        );
        jPanelRecordLabelLayout.setVerticalGroup(
            jPanelRecordLabelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanelRecordLabelLayout.createSequentialGroup()
                .addComponent(jPanelRecordLabelAux, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPaneRecordLabels, javax.swing.GroupLayout.DEFAULT_SIZE, 130, Short.MAX_VALUE)
                .addContainerGap())
        );

        jPanelFrame.setBorder(javax.swing.BorderFactory.createTitledBorder("Frame"));
        jPanelFrame.setPreferredSize(new java.awt.Dimension(0, 0));

        jPanelFrameEdit.setLayout(new java.awt.GridBagLayout());

        jButtonFrameEdit.setText("Edit");
        jButtonFrameEdit.setToolTipText("Edit selected frame");
        jButtonFrameEdit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonFrameEditActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.ipadx = 51;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        jPanelFrameEdit.add(jButtonFrameEdit, gridBagConstraints);

        jLabelFrameId.setText("Id: ");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        jPanelFrameEdit.add(jLabelFrameId, gridBagConstraints);

        jLabelFrameValue.setText("none");
        jLabelFrameValue.setMaximumSize(new java.awt.Dimension(40, 17));
        jLabelFrameValue.setMinimumSize(new java.awt.Dimension(40, 17));
        jLabelFrameValue.setPreferredSize(new java.awt.Dimension(40, 17));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        jPanelFrameEdit.add(jLabelFrameValue, gridBagConstraints);

        jPanelNewSequence.setLayout(new java.awt.GridBagLayout());

        jLabelStartId.setText("Start Frame: ");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.gridwidth = 2;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        jPanelNewSequence.add(jLabelStartId, gridBagConstraints);

        jLabelEndId.setText("End Frame: ");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.gridwidth = 2;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        jPanelNewSequence.add(jLabelEndId, gridBagConstraints);

        jLabelStartValue.setText("none");
        jLabelStartValue.setMaximumSize(new java.awt.Dimension(40, 17));
        jLabelStartValue.setMinimumSize(new java.awt.Dimension(40, 17));
        jLabelStartValue.setPreferredSize(new java.awt.Dimension(40, 17));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        jPanelNewSequence.add(jLabelStartValue, gridBagConstraints);

        jButtonStartSet.setText("Set");
        jButtonStartSet.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonStartSetActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        jPanelNewSequence.add(jButtonStartSet, gridBagConstraints);

        jLabelEndValue.setText("none");
        jLabelEndValue.setMaximumSize(new java.awt.Dimension(40, 17));
        jLabelEndValue.setMinimumSize(new java.awt.Dimension(40, 17));
        jLabelEndValue.setPreferredSize(new java.awt.Dimension(40, 17));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        jPanelNewSequence.add(jLabelEndValue, gridBagConstraints);

        jButtonEndSet.setText("Set");
        jButtonEndSet.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonEndSetActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        jPanelNewSequence.add(jButtonEndSet, gridBagConstraints);

        jButtonReset.setText("Reset");
        jButtonReset.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonResetActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        jPanelNewSequence.add(jButtonReset, gridBagConstraints);

        jButtonSaveNewSequence.setText("New");
        jButtonSaveNewSequence.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonSaveNewSequenceActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.ipadx = 13;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        jPanelNewSequence.add(jButtonSaveNewSequence, gridBagConstraints);

        jLabelTotalId.setText("Total selected:");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.gridwidth = 2;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        jPanelNewSequence.add(jLabelTotalId, gridBagConstraints);

        jLabelTotalValue.setText("none");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        jPanelNewSequence.add(jLabelTotalValue, gridBagConstraints);

        jButtonSaveChanges.setText("Save");
        jButtonSaveChanges.setEnabled(false);
        jButtonSaveChanges.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonSaveChangesActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 3;
        jPanelNewSequence.add(jButtonSaveChanges, gridBagConstraints);

        jListFrameLabels.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        jListFrameLabels.setToolTipText("Set frame label");
        jListFrameLabels.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
                jListFrameLabelsValueChanged(evt);
            }
        });
        jScrollPaneFrameLabel.setViewportView(jListFrameLabels);

        jLabelFrameLabel.setText("Label:");

        jLabelFrameLabelValue.setText("none");

        javax.swing.GroupLayout jPanelFrameLayout = new javax.swing.GroupLayout(jPanelFrame);
        jPanelFrame.setLayout(jPanelFrameLayout);
        jPanelFrameLayout.setHorizontalGroup(
            jPanelFrameLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanelFrameLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanelFrameLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(jScrollPaneFrameLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 281, Short.MAX_VALUE)
                    .addComponent(jPanelNewSequence, javax.swing.GroupLayout.DEFAULT_SIZE, 281, Short.MAX_VALUE)
                    .addComponent(jPanelFrameEdit, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 281, Short.MAX_VALUE)
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanelFrameLayout.createSequentialGroup()
                        .addComponent(jLabelFrameLabel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jLabelFrameLabelValue)))
                .addContainerGap())
        );
        jPanelFrameLayout.setVerticalGroup(
            jPanelFrameLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanelFrameLayout.createSequentialGroup()
                .addComponent(jPanelFrameEdit, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(jPanelFrameLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabelFrameLabel)
                    .addComponent(jLabelFrameLabelValue))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPaneFrameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 130, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jPanelNewSequence, javax.swing.GroupLayout.DEFAULT_SIZE, 181, Short.MAX_VALUE)
                .addContainerGap())
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                    .addComponent(jPanelFrames, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jPanelRecordings, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                    .addComponent(jPanelProjective, javax.swing.GroupLayout.DEFAULT_SIZE, 671, Short.MAX_VALUE)
                    .addComponent(jPanelPreview, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jPanelFrame, javax.swing.GroupLayout.DEFAULT_SIZE, 317, Short.MAX_VALUE)
                    .addComponent(jPanelRecordLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(jPanelPlay, javax.swing.GroupLayout.DEFAULT_SIZE, 259, Short.MAX_VALUE))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jPanelPlay, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jPanelRecordLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jPanelFrame, javax.swing.GroupLayout.DEFAULT_SIZE, 428, Short.MAX_VALUE))
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                            .addComponent(jPanelProjective, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(jPanelRecordings, javax.swing.GroupLayout.PREFERRED_SIZE, 525, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                            .addComponent(jPanelPreview, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(jPanelFrames, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void jButtonPreviousActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonPreviousActionPerformed
        jListFrames.setSelectedIndex(skeletonProjective.previousFrameIndex()-1);
        frameSelected = skeletonProjective.getCurrentFrame();
        jLabelFrameValue.setText(Integer.toString(frameSelected.getNumber()));
        setPreviewSelected();
        jPanelProjective.repaint();
    }//GEN-LAST:event_jButtonPreviousActionPerformed

    private void jButtonNextActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonNextActionPerformed
        jListFrames.setSelectedIndex(skeletonProjective.nextFrameIndex()-1);
        frameSelected = skeletonProjective.getCurrentFrame();
        jLabelFrameValue.setText(Integer.toString(frameSelected.getNumber()));
        setPreviewSelected();
        jPanelProjective.repaint();
    }//GEN-LAST:event_jButtonNextActionPerformed

    private void jTextFieldPathActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jTextFieldPathActionPerformed
        setRecPath();
    }//GEN-LAST:event_jTextFieldPathActionPerformed

    private void jListRecordingsValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_jListRecordingsValueChanged
        // TODO: jListRecordingsValueChanged
        if(! evt.getValueIsAdjusting()) return;
            
        if(! jListRecordings.isSelectionEmpty()) {
            openRecording();
            createFrameList();
            jPanelProjective.repaint();
            cretePreview();
        }
    }//GEN-LAST:event_jListRecordingsValueChanged

    private void jListFramesValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_jListFramesValueChanged
        // TODO: jListFramesValueChanged
        if(! evt.getValueIsAdjusting()) return;
        
        if(! jListFrames.isSelectionEmpty() ) {
            skeletonProjective.selectFrame(jListFrames.getSelectedIndex());
            frameSelected = skeletonProjective.getCurrentFrame();
            showFrameLabel();
            jPanelProjective.repaint();
            setPreviewSelected();
        }
    }//GEN-LAST:event_jListFramesValueChanged

    private void jButtonSetPathActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonSetPathActionPerformed
        setRecPath();
        // TODO: check if path exists
        // if path == "", reset 
    }//GEN-LAST:event_jButtonSetPathActionPerformed

    private void jFormattedTextFieldFPSActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jFormattedTextFieldFPSActionPerformed
        jFormattedTextFieldFPS.setValue(Math.abs(((Long)jFormattedTextFieldFPS.getValue()).longValue()));
    }//GEN-LAST:event_jFormattedTextFieldFPSActionPerformed

    private void jButtonPlayActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonPlayActionPerformed
        jButtonNext.setEnabled(false);
        jButtonPrevious.setEnabled(false);
        jButtonPlay.setEnabled(false);
        jButtonStop.setEnabled(true);
        
        skeletonProjective.selectFrame(1);
        jPanelProjective.repaint();
        setPreviewSelected();
        
        playTimer = new Timer((int)(1000.0/((Long)jFormattedTextFieldFPS.getValue()).longValue()), taskPerformerPlay);
        playTimer.setRepeats(true);
        playTimer.start();
    }//GEN-LAST:event_jButtonPlayActionPerformed

    private void jButtonStopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonStopActionPerformed
        playTimer.stop();
        jButtonStop.setEnabled(false);
        jButtonNext.setEnabled(true);
        jButtonPrevious.setEnabled(true);
        jButtonPlay.setEnabled(true);
    }//GEN-LAST:event_jButtonStopActionPerformed

    private void jButtonFrameEditActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonFrameEditActionPerformed
        if(skeletonProjective != null)  {
            new SkeletonEdit(skeletonProjective.getCurrentFrame()).setVisible(true);
        } else {
            JOptionPane.showMessageDialog(null, "Error", "No frame selected!", JOptionPane.ERROR_MESSAGE);
        }
    }//GEN-LAST:event_jButtonFrameEditActionPerformed

    private void jButtonStartSetActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonStartSetActionPerformed
        if(frameSelected != null) {
            if(frameEnd != null) {
                if(frameEnd.getNumber() < frameSelected.getNumber()) {
                    JOptionPane.showMessageDialog(null, "Ending index smaller than starting index.", 
                            "Error", JOptionPane.ERROR_MESSAGE);
                    return;
                }
                jLabelTotalValue.setText(Integer.toString(frameEnd.getNumber()-frameSelected.getNumber()+1));
            }
            frameStart = frameSelected;
            jLabelStartValue.setText(Integer.toString(frameStart.getNumber()));
            
        }
    }//GEN-LAST:event_jButtonStartSetActionPerformed

    private void jButtonEndSetActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonEndSetActionPerformed
        if(frameSelected != null) {
            if(frameStart != null) {
                if(frameStart.getNumber() > frameSelected.getNumber()) {
                    JOptionPane.showMessageDialog(null, "Starting index greater than ending index.", 
                            "Error", JOptionPane.ERROR_MESSAGE);
                    return;
                }
                jLabelTotalValue.setText(Integer.toString(frameSelected.getNumber()-frameStart.getNumber()+1));
            }
            frameEnd = frameSelected;
            jLabelEndValue.setText(Integer.toString(frameEnd.getNumber()));
        }
    }//GEN-LAST:event_jButtonEndSetActionPerformed

    private void jButtonResetActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonResetActionPerformed
        frameStart = null;
        frameEnd = null;
        jLabelTotalValue.setText("none");
        jLabelStartValue.setText("none");
        jLabelEndValue.setText("none");
    }//GEN-LAST:event_jButtonResetActionPerformed

    private void jButtonSaveNewSequenceActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonSaveNewSequenceActionPerformed
        try{
           Integer.parseInt(jLabelTotalValue.getText());
           new SaveSequence(this).setVisible(true);
        } 
        catch(NumberFormatException e){
            JOptionPane.showMessageDialog(null, "Not a valid selection.", 
                            "Error", JOptionPane.ERROR_MESSAGE);
        }
    }//GEN-LAST:event_jButtonSaveNewSequenceActionPerformed

    private void jButtonRefreshActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonRefreshActionPerformed
        if(recPath == null || recPath.equals("")) return;
        createFileList();
        if(recordigns == null) return;
        openRecording();
        createFrameList();
        cretePreview();
    }//GEN-LAST:event_jButtonRefreshActionPerformed

    private void jListRecordLabelsValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_jListRecordLabelsValueChanged
        if(! evt.getValueIsAdjusting()) return;
        
        String s;
        if(! jListRecordLabels.isSelectionEmpty() ) {
            if(! (s = (String)jListRecordLabels.getSelectedValue()).equalsIgnoreCase(jLabelRecordLabelValue.getText()) ) {
                jLabelRecordLabelValue.setText(s);
                change = true;
                jButtonSaveChanges.setEnabled(true);
                
                Sequence.Builder seq = sequence.toBuilder();
                seq.setLabel(s);
                sequence = seq.build();
            }
        }
    }//GEN-LAST:event_jListRecordLabelsValueChanged

    private void jListFrameLabelsValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_jListFrameLabelsValueChanged
        if(! evt.getValueIsAdjusting()) return;
        
        String s;
        if(! jListFrameLabels.isSelectionEmpty() ) {
            if(! (s = (String)jListFrameLabels.getSelectedValue()).equalsIgnoreCase(jLabelFrameLabelValue.getText()) ) {
                jLabelFrameLabelValue.setText(s);
                change = true;
                jButtonSaveChanges.setEnabled(true);
                
                if(frameStart != null && frameEnd != null) 
                // Multiple frames
                {
                    Sequence.Builder seq = sequence.toBuilder();
                    for(Frame fr : seq.getFrameList()) {
                        if(fr.getNumber() >= frameStart.getNumber() && fr.getNumber() <= frameEnd.getNumber()) {
                            Frame.Builder tmpFr = fr.toBuilder();
                            tmpFr.setLabel(s);
                            seq.setFrame(fr.getNumber()-1, tmpFr.build());
                        }
                    }
                    sequence = seq.build();
                } else if (frameSelected != null) 
                // Single frame
                {
                    Sequence.Builder seq = sequence.toBuilder();
                    Frame.Builder fr = seq.getFrame(frameSelected.getNumber()).toBuilder();
                    fr.setLabel(s);
                    seq.setFrame(fr.getNumber()-1, fr.build());
                    sequence = seq.build();
                }
            }
        }
    }//GEN-LAST:event_jListFrameLabelsValueChanged

    private void jButtonSaveChangesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonSaveChangesActionPerformed
        FileOutputStream output;
        try {
            output = new FileOutputStream(recording);
            sequence.writeTo(output);
            output.close();
            jButtonSaveChanges.setEnabled(false);
            System.out.println("File "+recording.getName()+" saved.");
        } catch (IOException ex) {
            System.err.println("Error: file "+recording.getName()+" not saved!");
            ex.printStackTrace();
        }
    }//GEN-LAST:event_jButtonSaveChangesActionPerformed
        
    /**
     * Initial Load
     */
    private void initSetupAndLoad() {
        idToFrame = new HashMap<>();
        
        // Windows Position 
        setLocation(Integer.parseInt(preferences.getProperty("ViewerWindowPositionX")), 
                    Integer.parseInt(preferences.getProperty("ViewerWindowPositionY")));
        
        createRecordLabelList();
        createFrameLabelList();
        
        // Recordings
        setRecPath(preferences.getProperty("REC"));
        if(recPath == null || recPath.equals("")) return;
        createFileList();
        if(recordigns == null) return;
        
        skeletonProjective = new SkeletonProjective();
        skeletonProjective.setBounds(6,19, 640, 480);
        jPanelProjective.add(skeletonProjective); 
        openRecording();
        createFrameList();
               
        // Preview
        // TODO: tweak increment
        jScrollPanePreview.getHorizontalScrollBar().setUnitIncrement(65);
        cretePreview();
    }  
    
    private void setRecPath(String path) {
        // TODO: check if valid recording path
        jTextFieldPath.setText(path);
        recPath = path;
    }
        
    private void setRecPath() {
        // TODO: chekc if valid recording path
        recPath = jTextFieldPath.getText();
    }
    
    private void createFileList() {
        recordigns = null;
        dir = new File(recPath);
        
        if(!dir.isDirectory()) {
            // TODO: Report Error !
            return;
        }   
                
        recordigns = dir.list();
        if(recordigns.length == 0) return;
        java.util.Arrays.sort(recordigns);
   
        // TODO: Show only valid recording files!
        jListRecordings.setListData(recordigns);
        jListRecordings.setSelectedIndex(0);
    }
    
    private void openRecording() {
        recording = new File(recPath+File.separator+(String)jListRecordings.getSelectedValue());  
        try {    
            sequence = Sequence.parseFrom(new FileInputStream(recording));
            skeletonProjective.setNewSequence(sequence);
            String label = sequence.getLabel();
            if(label == null || label.equals("")) {
                jLabelRecordLabelValue.setText("none");
            } else {
                jLabelRecordLabelValue.setText(label);
            }
            //System.out.println("Open: "+sequence.getName());
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
        
    private void createFrameList() {
        idToFrame.clear();
        PrintfFormat pf = new PrintfFormat("%4d");
        
        String[] framesString = new String[sequence.getFrameCount()];
        int i=0;
        for(Frame f:sequence.getFrameList()) {
            framesString[i++] = "Frame "+ pf.sprintf(f.getNumber());
            idToFrame.put(f.getNumber(), f);
        }
        
        frameSelected = sequence.getFrame(0);
        jListFrames.setListData(framesString); 
        jListFrames.setSelectedIndex(skeletonProjective.firstFrameIndex()-1);
        showFrameLabel();
        
        jButtonNext.setEnabled(true);
        jButtonPrevious.setEnabled(true);
        jButtonPlay.setEnabled(true);
        jButtonStop.setEnabled(false);
        //System.out.println("createFrameList: "+sequence.getName());
    }
    
    private void createRecordLabelList() {
        java.util.Arrays.sort(recordLabels);
        jListRecordLabels.setListData(recordLabels);
    }
    
    private void createFrameLabelList() {
        java.util.Arrays.sort(frameLabels);
        jListFrameLabels.setListData(frameLabels);
    }
    
    private void showFrameLabel() {
        if(frameSelected != null) {
            jLabelFrameValue.setText(Integer.toString(frameSelected.getNumber()));
            String s = frameSelected.getLabel();
            if (s.equalsIgnoreCase("") || s == null) {
                jListFrameLabels.clearSelection();
                jLabelFrameLabelValue.setText("");
            } else {
                jLabelFrameLabelValue.setText(s);
            }
        } else {
            jListFrameLabels.clearSelection();
            jLabelFrameLabelValue.setText("");
        }
    }
    
    private void cretePreview() {
        // System.out.println("cretePreview");      
        int w = 200, h = (int) (w * 0.75);
        //SkeletonPreview preview; 
        jPanelContainer.removeAll();
        for(Frame frame:sequence.getFrameList()) {
            jPanelContainer.add(new SkeletonPreview(this, frame, w, h));
        }        
        jPanelContainer.validate();
    }
    
    private void setPreviewSelected() {
        ((SkeletonPreview)jPanelContainer.getComponent(jListFrames.getSelectedIndex())).setSelected();
    }
 
    ActionListener taskPerformerPlay = new ActionListener() {
        public void actionPerformed(ActionEvent evt) {

            if(skeletonProjective.getCurrentFrameID() < skeletonProjective.getFrameCount()-1) {
                jListFrames.setSelectedIndex(skeletonProjective.nextFrameIndex() - 1);
                setPreviewSelected();
                jPanelProjective.repaint();
            }
            else {
                jButtonPlay.setEnabled(true);
                jButtonNext.setEnabled(true);
                jButtonPrevious.setEnabled(true);
                jButtonStop.setEnabled(false);
                playTimer.stop();
            } 
        }
    };
    
    /**
     * 
     */
    public SkeletonProjective getSkeletonProjective() {
        return skeletonProjective;
    }
    
    public void setSkeletonProjectiveAndRepaint(Frame f) {
        frameSelected = f;
        showFrameLabel();
        jListFrames.setSelectedIndex(skeletonProjective.selectFrame(f)-1);
        jPanelProjective.repaint();
    }

    public int getStartIndex() {
        return Integer.parseInt(jLabelStartValue.getText());
    }
    
    public int getEndIndex() {
        return Integer.parseInt(jLabelEndValue.getText());
    }
    
    public int getSelectionCount() {
        return Integer.parseInt(jLabelTotalValue.getText());
    }
    
    public String getSequenceLabel() {
        return jLabelRecordLabelValue.getText();
    }
    
    /*
     * Debug output
     */
    private void printSequence(Sequence sequence) {
        System.out.println("####################################################");
        System.out.println("Sequence: "+sequence.getName());
        for(Frame frame:sequence.getFrameList()) {
            System.out.println("  Frame "+frame.getNumber());
            System.out.println("   CoM: "+printPoint3D(frame.getSkeleton().getCoM()));
            for(Joint joint:frame.getSkeleton().getJointsList()) {
                System.out.println("    Type: "+joint.getType());
                System.out.println("    RW: "+ printPoint3D(joint.getRealWorld()));
                System.out.println("    PR: "+ printPoint3D(joint.getProjective()));
                System.out.println("    Conf: "+joint.getConfidence());
            }
        }
        System.out.println("####################################################");
    }
    
    private String printPoint3D(Point3D p) {
        return ("X: "+ p.getX()+", Y: "+p.getY() + ", Z: "+p.getZ());
    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName()); 
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(Viewer.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                new Viewer().setVisible(true);
            }
        });
    }
    
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton jButtonEndSet;
    private javax.swing.JButton jButtonFrameEdit;
    private javax.swing.JButton jButtonNext;
    private javax.swing.JButton jButtonPlay;
    private javax.swing.JButton jButtonPrevious;
    private javax.swing.JButton jButtonRefresh;
    private javax.swing.JButton jButtonReset;
    private javax.swing.JButton jButtonSaveChanges;
    private javax.swing.JButton jButtonSaveNewSequence;
    private javax.swing.JButton jButtonSetPath;
    private javax.swing.JButton jButtonStartSet;
    private javax.swing.JButton jButtonStop;
    private javax.swing.JFormattedTextField jFormattedTextFieldFPS;
    private javax.swing.JLabel jLabelEndId;
    private javax.swing.JLabel jLabelEndValue;
    private javax.swing.JLabel jLabelFPS;
    private javax.swing.JLabel jLabelFrameId;
    private javax.swing.JLabel jLabelFrameLabel;
    private javax.swing.JLabel jLabelFrameLabelValue;
    private javax.swing.JLabel jLabelFrameValue;
    private javax.swing.JLabel jLabelRecordLabelId;
    private javax.swing.JLabel jLabelRecordLabelValue;
    private javax.swing.JLabel jLabelStartId;
    private javax.swing.JLabel jLabelStartValue;
    private javax.swing.JLabel jLabelTotalId;
    private javax.swing.JLabel jLabelTotalValue;
    private javax.swing.JList jListFrameLabels;
    private javax.swing.JList jListFrames;
    private javax.swing.JList jListRecordLabels;
    private javax.swing.JList jListRecordings;
    private javax.swing.JPanel jPanelContainer;
    private javax.swing.JPanel jPanelFrame;
    private javax.swing.JPanel jPanelFrameEdit;
    private javax.swing.JPanel jPanelFrames;
    private javax.swing.JPanel jPanelNewSequence;
    private javax.swing.JPanel jPanelPlay;
    private javax.swing.JPanel jPanelPlayAux;
    private javax.swing.JPanel jPanelPreview;
    private javax.swing.JPanel jPanelProjective;
    private javax.swing.JPanel jPanelRecListButton;
    private javax.swing.JPanel jPanelRecordLabel;
    private javax.swing.JPanel jPanelRecordLabelAux;
    private javax.swing.JPanel jPanelRecordings;
    private javax.swing.JScrollPane jScrollPaneFrameLabel;
    private javax.swing.JScrollPane jScrollPaneFrames;
    private javax.swing.JScrollPane jScrollPanePreview;
    private javax.swing.JScrollPane jScrollPaneRecordLabels;
    private javax.swing.JScrollPane jScrollPaneRecordings;
    private javax.swing.JTextField jTextFieldPath;
    // End of variables declaration//GEN-END:variables
}
